//DACKEL 2.0 with support for the CAEN V792 QDC, 20070405

#include <iostream>
#include <fstream>
#include <iomanip>
#include <csignal>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <zlib.h>

extern "C" {
#include "sis3100_vme_calls.h"
}

#include "timemeasure.h"
#include "teebuf.h"
#include "IOError.h"
#include "ConfigReader.h"
#include "ADC_DL642A.h"
#include "TDC_V767.h"
#include "TimeCounter_DL643A1.h"
#include "Latch_SIS3600.h"
#include "DigitalIO_DL636F.h"
#include "Counter_DL636G1.h"
#include "StartStop.h"
#include "EventStruct.h"
#include "BufferedVMEReader.h"
#include "dackel_date.h"
//#include "dkl_header.h"
#include "DklHeader.h"
#include "tdc_channels.h"
#include "QDC_V792.h"
#include "counters.h"
#include "inconsistent.h"

using namespace std;


#define TIME_PROFILE 1

#define CYCLE_FN "/data/cycle.count"

// -------- buffers ------- //
#define     BUFSIZE      1000

EventStruct ev[BUFSIZE];
// counts the number of stops per event
const static u_int32_t TDC_STOPS = 4;
u_int32_t        tdc_numstops[BUFSIZE]; 

// contains the number of events with zero tdc stops per cycle
u_int32_t        tdc_zeroevents; 

//changed 20070328
//const u_int32_t noc=6;      // number of counters


// increased from 10 to 11 on 20070402 by alex
// the new counter indicates for every cycle wheter it is valid or not
// dackel from now continues, if the number of events in the several
// vme devices differ. the cycle then is invalid, a can not be used!
const u_int32_t noc=11;      // number of counters 

#define QDC_USED_CHANNELS 0xfff // use 12 channels (0..11)
#define QDC_USED_THRESHOLD 0    // no QDC threshold used

//u_int32_t  counterbuf[noc]; // size = noc * sfs_length * sf_loops
// will be allocated somewhere else
// see DklHeader.h

// -------- global variables -------- //
char *log_fn             = "dackel.log";
char *def_cfg_fn         = "/etc/dackel2.cfg";
int adc0_addr            = 0xb100;
int adc1_addr            = 0xb200;
int adc2_addr            = 0xb300;
int adc3_addr            = 0xb400;
int tdc_addr             = 0;
int tdc_ch1              = 0;
int tdc_ch2              = 1;
int tdc_width            = 0;
int tdc_offset           = 0;
int tc_addr              = 0;
int latch_addr           = 0;
int cnt1_addr            = 0;
int cnt2_addr            = 0;
int io_addr              = 0;
int startstop_addr       = 0;
int qdc_addr             = 0;
int measuretime          = 10; //in seconds
char *mtus               = "100ns";
u_int16_t mtu            = 0;
int sleeptime            = 1; //microseconds
char *dev_fn             = "/dev/sis1100";
char *out_fn             = "out.dkl";
int gz_level             = 3;
int gz_strategy          = Z_DEFAULT_STRATEGY;
char *comment            = "alles für den dackel,alles für den club,"
                           "unser leben für den hund!";
u_int32_t min_delta      = 16;
u_int32_t max_delta      = 32;
u_int32_t tdc_br_cs      = 1000;
u_int32_t tdc_br_cn      = 5;
char *sf_schema          = "01";
u_int32_t sfs_length     = 0;
u_int32_t sf_loops       = 2;
u_int32_t sf_pause       = 50000; //microseconds
u_int32_t only_test      = 0;

u_int8_t status_flags    = 0;
/* status flags:
	 bit 7: alternates between cycles (c0->0, c1->1, c2->0, c3->1,...)
	 bit 6: spin flip state for cycle

	 bit 5-3: number of tdc stops

   bit 2-0: not used yet

	 this is mapped to the highest 8 bit (i.e. bits 31-24) of the latch data
*/

u_int32_t fcID           = 0; //first cycle ID: done 2006/12/15
u_int32_t cur_cycle      = 0;
											 
streambuf *original_cerr_sb = 0;
int    out;
gzFile gzout;

int                 crate=-1;
ADC_DL642A          *adc0,*adc1,*adc2,*adc3;
TDC_V767            *tdc;
Latch_SIS3600       *latch;
TimeCounter_DL643A1 *tc;
Counter_DL636G1     *cnt1,*cnt2;
BufferedVMEReader   *tdc_br;
DigitalIO_DL636F    *io;
StartStop           *startstop;
QDC_V792            *qdc;

u_int32_t hitcounter=0, readcounter=0, delta=0;
u_int32_t ev_count=0; //contains the total number of events 
u_int32_t rate_hc=0, rate_tc=0;
double    rate;
u_int32_t display_hc=0;

u_int32_t           last_tdc_en=-1; // last tdc event num
u_int32_t           tdc_eco=0;      // tdc event counter overflows

double gzWriteTime = 0;

// this register contains information about the measurement modus
// bit  0: Beam
// bit  1: Main Shutter (H113)
// bit  2: Shutter-Up
// bit  3: Shutter-Down
// bit  4: Source 1
// bit  5: Source 2
// bit  6: Source 3
// bit  7: Source 4
// bit  8: Source 5
// bit  9: Scan
// bit 10: Test
u_int16_t modus=1;   // default is  measurement with beam

// -- functions in main.cpp -- //
void show_settings();
void show_help(char *progname);
void proc_opts(int argc,char *argv[]);
void init_hw();
void read_hw();
void write_data();
u_int32_t readTDCEvent(u_int32_t *buf, u_int32_t bufsize,
											 u_int32_t *tdc_numstops, u_int32_t *tdc_zeroevents)
		throw (IOError);
void show_SIS3100_status(int handle) throw(IOError);
void signal_handler(int signal);
void safe_exit(int r);
void read_config_file(int argc,char *argv[]);
void setFlipper(unsigned char c);
void read_cycleno();
void write_nextcycleno();
void showErrorInfo( IOError &ioe );
void counterInfo();
void deadTime();

/*****************************************************************************/
int main(int argc, char *argv[])
/*****************************************************************************/
{
		signal(SIGINT,signal_handler); // install handler for CTRL-C

		original_cerr_sb = cerr.rdbuf(); // save original readbuffer of cerr

		stringstream tmplog;
		cerr.rdbuf( new teebuf(original_cerr_sb, tmplog.rdbuf()) );

		cerr << "----------------------------------------"
				 << "----------------------------------------\n"
				 << "dackel 2.0                                           "
				 << "built: " << __DATE__ << " " << __TIME__ << endl
				 << "----------------------------------------"
				 << "----------------------------------------\n\n";

    read_config_file(argc,argv);  // process options from config_file
		proc_opts(argc,argv);         // process options given on command line

		// open log file
		cerr.flush();
		ofstream logs(log_fn);
		if(!logs) {
				cerr << "error: could not open log file \"" << log_fn << "\"" << endl;
				exit(1);
		}
		// from now on write directly to log file
		cerr.rdbuf(new teebuf(original_cerr_sb,logs.rdbuf()));

		//determine the first cycles' number
		try { read_cycleno(); } catch( IOError ioe) {
				cerr << "---- ERROR: could not read cycle no! ----\n";
				cerr << ioe.getMsg();
				exit(1);
		}

		DklHeader dklheader(modus,comment,sfs_length,sf_loops,fcID,noc);
		cerr << "dklheader:"
				 << " modus:0x" << hex << dklheader.modus << dec
				 << " comment:\"" << dklheader.comment
				 << "\" sfs_length:" << dec << sfs_length
				 << " sf_loops:" << dec << sf_loops
				 << " fcID: " << dec << fcID
				 << " noc:" << noc << "\n\n";

		cerr << "started "
         << dklheader.date.year << "-"
				 << (int)dklheader.date.month << "-"
				 << (int)dklheader.date.day << " " 
				 << (int)dklheader.date.hour << ":"
				 << (int)dklheader.date.minute << ":"
				 << (int)dklheader.date.second
				 << endl << endl;
  
		if(only_test) { show_settings(); exit(0); }

#if TIME_PROFILE
		cerr << "compiled with TIME_PROFILE\ninitializing...";
		if(TM_INIT() !=0) { cerr << "error\n"; return 1; }
		cerr << "cpu frequency: "<< tm_cpu_freq << " Hz\n\n";
#endif

		cerr << "open output file...";
		// open file for data output
		if( (out = creat(out_fn,0644))==-1 ) {
				cerr << "ERROR: could not open output file \"" << out_fn << "\"\n\n";
				cerr.flush(); logs.flush(); exit(1);
		}
		cerr << "ok, ";

		// write uncompressed header to outputfile
		cerr << "writing dklheader..."; dklheader.toFile(out);	cerr << "ok\n";

		// start compressed section of output file
		if( !(gzout = gzdopen(dup(out),"wb")) ) {
				cerr << "ERROR: gzdopen() returned zero\n\n";
				cerr.flush(); logs.flush(); exit(1);
		}
		if( gzsetparams(gzout,gz_level,gz_strategy) != Z_OK ) {
				cerr << "ERROR: gzsetparams() did not return Z_OK\n\n";
				cerr.flush(); logs.flush(); exit(1);      
		}

		init_hw();

		logs.flush();

//	cerr << "measuring...\n";

		usleep(500);

		try {
				cur_cycle=0;
				
				for(u_int32_t sf_loop=0; sf_loop<sf_loops; sf_loop++) {

						cerr << "\nsl_loop: " << sf_loop << "\n";

						for(u_int32_t sfs_index=0; sfs_index < sfs_length; sfs_index++) {

								u_int32_t consistency = 0; //should stay 0 if no error occurs;

								status_flags ^= 0x80; //toggle bit 7
								setFlipper(sf_schema[sfs_index]);

								cerr << "----------------------------------------"
										 << "----------------------------------------\n";

								cerr << "setting spin flipper to " << sf_schema[sfs_index]
										 << "  (status_flags=0x"
										 << hex << (u_int16_t)status_flags << dec << ") "
										 << "  cur. cycle: " << cur_cycle
										 << "  total: " << dklheader.cycle_count
										 << endl;

								usleep(sf_pause);

								time_t start = time(0);
								char timestr[100];
								strftime(timestr,100,"%y-%m-%d %H:%M:%S",localtime(&start));
								
								double dt=0,old_dt=0;
//								io->setO1(1);

								cnt1->reset();
								cnt2->reset();

                //070218 added by alex
								latch->clearFIFO();
								qdc->SoftwareReset();
								/// tdcs are cleared, output buffer is cleared,
								/// readout controller is reset, event counter is set to 0
								tdc->clearRegisters();   

								tc->reset();
								readcounter = 0;
								hitcounter = 0;
								last_tdc_en = -1; tdc_eco = 0;

								//CAUTION: measuretime must be given in seconds
								//         assuming a 10 MHz Clock is used
								startstop->reset();
								startstop->setPreset1((u_int32_t)(measuretime*1e7));
								startstop->setControlRegister(StartStop::COUNTER1_ENABLED);
								startstop->start();
								
								tdc_zeroevents=0;

								while(1) {

										if( startstop->getControlRegister() &
												StartStop::COUNTING_FINISHED )	break;

										if(sleeptime != 0) usleep(sleeptime);
										
//										if(!qdc->BufferEmpty()) {
//												hitcounter = qdc->GetEventCounter();
//												cerr << "qdc->GetEventCounter()="
//														 << hitcounter << endl;
//										}
										// take acounter as reference since the QDC does not have a counter
										hitcounter = cnt1->getC();
										delta = hitcounter - readcounter;
	  
										if(delta>max_delta) delta = max_delta;

										if( hitcounter & 1000 == 1000) {
//										cout << right << "\033[1Adt=" << setw(9)
												cout << right << "\rdt=" << setw(9)
//											   << startstop->getTimerCounter()
														 << startstop->getCounter1()
														 << " de=" << setw(5) << hitcounter - display_hc  
														 << " delta=" << setw(3) <<delta
														 << "(" << setw(3) <<(hitcounter-readcounter) << ")"  
														 << setfill('0')
														 << " lgzw_dt=" << setprecision(4)
														 << setw(9) << tm_secs
														 << "s rate=" << setprecision(4) << setw(5)
														 << rate << "kHz"
														 << "    ";
												old_dt = dt;
												display_hc=hitcounter;
										
												logs.flush();
										}
										
										min_delta=1;
										if( delta >= min_delta ) {

												try {
														read_hw();
												} catch( IOError ioe ) {
														showErrorInfo( ioe );
														consistency |= INLOOP_ERROR;
														cerr << "\n>> THIS CYCLE WILL BE "
																 << "MARKED AS INVALID <<\n";
														cerr << "consistency=" << hex
																 << consistency << endl;

														dklheader.setCounter( CYCLE_VALID_COUNTER,
																									cur_cycle,
																									consistency );
														break;
												}

												try {
												    write_data();
												} catch( IOError ioe ) {
														showErrorInfo( ioe );
														consistency |= WR_ERROR;
														cerr << "\n>> THIS CYCLE WILL BE "
																 << "MARKED AS INVALID <<\n";
														cerr << "consistency=" << hex
																 << consistency << endl;
														dklheader.setCounter( CYCLE_VALID_COUNTER,
																									cur_cycle,
																									consistency );
														break;
												}
												
												readcounter += delta;
										}

								}
				
								counterInfo();
								deadTime();

//								io->setO1(0);

								cerr << "\nfinished sf_loop: ";
				
								if(!consistency) {
										// read the rest

//										//hitcounter = qdc->GetEventCounter(); 				
										hitcounter = cnt1->getC();
										delta = hitcounter - readcounter;      
	
										cerr << delta << " events left in buffers - reading..."
												 << flush;

										try {
												read_hw();
										} catch( IOError ioe ) {
												showErrorInfo(ioe);
												consistency |= REMAIN_ERROR;
												cerr << "\n\n>> THIS CYCLE WILL BE "
														 << "MARKED AS INVALID <<\n";
												cerr << "consistency=" << hex
														 << consistency << endl;

												dklheader.setCounter(CYCLE_VALID_COUNTER,cur_cycle,
																						 consistency);
												
										}

										if( !consistency ) {
												cerr << "ok\n"; readcounter += delta;

												try {
														write_data();
												} catch( IOError ioe ) {
														showErrorInfo(ioe);
														consistency |= WR_ERROR;
														cerr << "\n\n>> THIS CYCLE WILL BE "
																 << "MARKED AS INVALID <<\n";
														cerr << "consistency=" << hex
																 << consistency << endl;
														dklheader.setCounter( CYCLE_VALID_COUNTER,
																									cur_cycle,
																									consistency );
												}
										}
								}
// finally removed by alex on 20070402 due to explicit wish of bastian ;-)
//								cerr << "there have been " << tdc_eco
//										 << " tdc event counter overflows (not an error)\n";

								if(tdc_zeroevents!=0) {
										cerr << "warning: there have been " << tdc_zeroevents
												 << " events with no TDC stops!" << endl;
								}
				
								//change on 20070402: now dackel continues if consistency check
								//fails, but marks the cycle as bad in one counter in DklHeader
      
								// check consistency
								u_int32_t qdc_hc = qdc->GetEventCounter();
								u_int32_t tdc_hc =  (last_tdc_en+1) + tdc_eco*1024;
								u_int32_t latch_status = latch->getStatus();
								u_int32_t tc_words = tc->getWords();
								
								if( qdc_hc != readcounter )  consistency |=  QDC_INCONSISTENT;
								if( tdc_hc != readcounter)   consistency |= TDC_INCONSISTENT;
								if( !(latch_status&0x100) )  consistency |= LATCH_INCONSISTENT;
								if( tc_words != 0 )          consistency |= TC_INCONSISTENT;
								
								if(consistency)
								{
										cerr << "consistency check:\n"
												 << " qdc: " << qdc_hc
												 << (qdc_hc==readcounter?" ok":" error")
												 << "\n   tdc: " << tdc_hc
												 << (tdc_hc==readcounter?" ok":" error")
												 << "  latch: "
												 << ((latch_status & 0x100) ?
														 "empty: ok" : " not empty: error")
												 << "  tc: " << tc_words
												 << ((tc_words==0)?" ok\n":" error\n")
			 
												 << endl;
										
                    //only print this messages if there have been no errors
										//before the comparision of QDC,TDC,TC and latch
                    //(otherwise the messages has been already been print)
										if(consistency<REMAIN_ERROR) {
												cerr << "\n\n>> THIS CYCLE WILL BE "
														 << "MARKED AS INVALID <<\n";
												cerr << "consistency=" << hex
														 << consistency << endl;
										}

										//removed on 20070402, no the cycle is marked as bad
										//throw IOError("number of events in hw is inconsistent!",0);
								}

								cerr << "\n             cycle:  total:  d1:  d2: "
										 << "(counts per cycle) time() timestr\n"
										 << "CYCLEINFO:00: "
										 << cur_cycle+fcID << " "
										 <<	hitcounter << " "
										 << cnt1->getA() << " "
										 << cnt1->getB() << " "
										 << start << " "
										 << timestr << endl;

								//cerr << "reading counters...";
								dklheader.setCounter(0,cur_cycle,cnt1->getA());
								dklheader.setCounter(1,cur_cycle,cnt1->getB());
								dklheader.setCounter(2,cur_cycle,cnt1->getC());
								dklheader.setCounter(3,cur_cycle,cnt2->getA());
								dklheader.setCounter(4,cur_cycle,cnt2->getB());
								dklheader.setCounter(5,cur_cycle,cnt2->getC());
								dklheader.setCounter(6,cur_cycle,startstop->getCounter1());
								dklheader.setCounter(7,cur_cycle,startstop->getCounter2());
								dklheader.setCounter(8,cur_cycle,startstop->getCounter3());
								dklheader.setCounter(9,cur_cycle,startstop->getTimerCounter());
								//this marks bad cycles if any exist
								dklheader.setCounter( CYCLE_VALID_COUNTER,
																			cur_cycle, consistency );
								//cerr << "ok\n\n";
								
								ev_count += hitcounter;
								cur_cycle++; write_nextcycleno();
						}
				}

		} catch(IOError ioe) {
				showErrorInfo(ioe);
				cerr.flush(); logs.flush(); 
				safe_exit(1);
		}

		// turning off spinflipper (2007-03-06)
		setFlipper('0');

		close(crate);
		gzclose(gzout); //this ends the compressed section in the output file

		cerr << hitcounter << " events total" << endl
				 << "meantime for gzwrite: "
				 << gzWriteTime/hitcounter << " seconds\n\n";

		dklheader.fileOK = 0; // ok, there were no errors so far
		dklheader.ev_count = ev_count;

		cerr << dklheader.infoString();

		//write file status: ok and number of events to header of output file
		lseek(out,0,0);
		try	{	dklheader.toFile(out); }
		catch(IOError ioe) {
				cerr << ioe.getMsg();
				exit(1);
		}

		close(out);

		return 0;
}
/*****************************************************************************/


/*---------------------------------------------------------------------------*/
void deadTime()
/*---------------------------------------------------------------------------*/
{
		cerr << "\ndeadtime = ("
				 << ((startstop->getCounter2() - startstop->getCounter1())/10)
				 << "+-"
				 << ((cnt2->getB() - startstop->getCounter1())/10)
				 << ")us  <=>  "
				 <<	(((double)startstop->getCounter2()
							-startstop->getCounter1())
						 /startstop->getCounter1() * 100 ) << "%"
				 << endl;
}
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
void counterInfo()
/*---------------------------------------------------------------------------*/
{
//for unknown reason this has to be done
//since the startstop card does only give the correct value on the second attempt
startstop->getCounter1();

							  cerr << "\nstartstop: cnt1=" << startstop->getCounter1()
										 << ",cnt2=" << startstop->getCounter2()
//										 << ",cnt3=" << startstop->getCounter3()
//										 << ",timer=" << startstop->getTimerCounter() 
										 << " counter2: A=" << cnt2->getA()
										 << ",B=" << cnt2->getB()
										 << ",C=" << cnt2->getC() << endl;
}
/*---------------------------------------------------------------------------*/


//TODO: give human readable info
/*---------------------------------------------------------------------------*/
void showErrorInfo( IOError &ioe )
/*---------------------------------------------------------------------------*/
{
		cerr << "catched IOError:\n" << ioe.getMsg() << endl
				 << "param: "
				 << ioe.getParam() << " (signed) = "
				 << (u_int32_t)ioe.getParam() << " (unsigned) = " << hex
				 << ioe.getParam() << " (hex)"
				 << endl << endl;

		cerr << "reading out module states:\n";
		try {
				cerr << hex
						 << "tdc: status1=0x" << tdc->getStatus1()
						 << " status2=0x" << tdc->getStatus2()
						 << " errorcode_tdc0=0x" << tdc->readTDCErrorCode(0)
						 << " errorcode_tdc1=0x" << tdc->readTDCErrorCode(1)
						 << "\n\n" << flush
						 << " qdc: status1=0x" << qdc->GetStatus1()
						 << " status2=0x" << qdc->GetStatus2()
						 << "latch: status=0x" << latch->getStatus() << endl
						 << "\n";
		} catch(IOError ioe) {
				cerr << "could not read status, catched IOError:\n" << ioe.getMsg()
						 << endl
						 << "param: "
						 << ioe.getParam() << " (signed) = "
						 << (u_int32_t)ioe.getParam() << " (unsigned) = " << hex
						 << ioe.getParam() << " (hex)"
						 << endl << endl;
		}

		cerr << "hitcounter = " << hitcounter << endl
				 << "readcounter = " << readcounter << endl;
}
/*---------------------------------------------------------------------------*/



/*---------------------------------------------------------------------------*/
void setFlipper(unsigned char c)
/*---------------------------------------------------------------------------*/
{
		if(c=='1') {
				io->setO2(1); // spin flipper = 1
				status_flags |= 0x40; // sets bit 6 to 1
    } else if(c=='0') {
				io->setO2(0); // spin fliper = 0
				status_flags &= ~0x40; // sets bit 6 to 0
		} 
		else throw IOError("setFlipper(): invalid Flipper state!",c);
}
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
void init_hw()
/*---------------------------------------------------------------------------*/
{
		// open sis1100/3100 pci-to-vme link
		if( !(crate=open(dev_fn, O_RDWR, 0)) )
		{
				cerr << "ERROR: could not open \"" << dev_fn << "\"" << endl;
				cerr.flush(); exit(1);
		}

		// instantiate vme objects
		tdc    = new TDC_V767(crate,tdc_addr);
		tdc_br = new BufferedVMEReader(tdc_br_cs,tdc_br_cn,tdc);
		latch  = new Latch_SIS3600(crate,latch_addr);
		tc     = new TimeCounter_DL643A1(crate,tc_addr);
		cnt1   = new Counter_DL636G1(crate,cnt1_addr);
		cnt2   = new Counter_DL636G1(crate,cnt2_addr);
		io     = new DigitalIO_DL636F(crate,io_addr);
		startstop = new StartStop(crate,startstop_addr);
		qdc       = new QDC_V792(crate,qdc_addr);

		cerr << "hw init: vmesysreset..." << flush;
		if(int r=vmesysreset(crate)) {
				cerr << "error: vmesysreset() returned " << r << endl << endl;
				cerr.flush();
				safe_exit(1);
		}
		cerr << "ok, sleeping 1 sec..."; sleep(1); cerr << "ok, ";

//		show_SIS3100_status(crate);

		try {
				//reset of startstop has to be done first!!!
				cerr << " init:\n" << flush;
				startstop->reset();
				cerr << "ok, ";

//								startstop->setTimerPreset(measuretime);
//								startstop->setControlRegister(
//										StartStop::TIMERPRESET_ENABLED
//										| mtu );							

				// init io
				cerr << "io..." << flush;
				io->setOutputs(0); //set all output to zero
				cerr << "ok, ";

				// init QDC
				cerr << "qdc..." << flush;
				qdc->SoftwareReset();
				qdc->DefineChannelBehaviour(QDC_USED_CHANNELS, QDC_USED_THRESHOLD);
				qdc->CountOnlyValidEvents();
				qdc->SetFastClearWindow(0);
				qdc->SetBit2Pattern(QDC_V792::BITSET_2_OVER_RANGE_ENABLED |
									QDC_V792::BITSET_2_LOW_THRESHOLD_ENABLED);
				cerr << "ok, ";

				// init TDC
				// TODO: set edge detection on all channels!
				cerr << "tdc..." << flush;
				tdc->reset(); sleep(2);
				tdc->setMode(TDC_V767::STOP_MATCH);
				tdc->setWindowWidth(tdc_width);
				tdc->setWindowOffset(tdc_offset);
				tdc->disableAllChannels();

				tdc->enableChannel(DET1_CHANNEL);
				tdc->enableChannel(DET2_CHANNEL);

				tdc->enSubTriggerTime();
				tdc->setRisingEdgeAll();
				tdc->setDataReady();
				cerr << "ok, ";
      
				// init Latch
				cerr << "latch..." << flush;
				latch->reset();
//removed 20060406_2346
//			latch->clrCoincidenceMode();
        //added 20060406_2346             //TAG: BASTIAN
				latch->setCoincidenceMode();
				latch->enNextClkLogic();
				latch->enExtNextMode(); //enable external trigger
				cerr << "ok, ";

				// init TimeCounter
				cerr << "tc..." << flush; tc->reset(); cerr << "ok,";

				// init Counter
				cerr << "counters..." << flush;
				cnt1->reset(); cnt2->reset();
				cerr << "ok\n";

				// init StartStop
//				cerr << setw(24) << "init startstop module";
//				startstop->reset();
//				cerr << "ok\n";
		} catch(IOError ioe) {
				cerr << "catched IOError:\n" << ioe.getMsg() << endl
						 << "param: "
						 << ioe.getParam() << " (signed) = "
						 << (u_int32_t)ioe.getParam() << " (unsigned) = " << hex
						 << ioe.getParam() << " (hex)\n\n"
						 << "strerror() returns: " << strerror(errno)
						 << endl << endl;

				cerr.flush();
				safe_exit(1);
		}
}
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
void read_config_file(int argc,char *argv[])
/*---------------------------------------------------------------------------*/
{
		// get config file name
		ConfigReader cr;
		try {
				cr.getConfigFileName(&argc,argv);
		} catch(IOError ioe) {
				cerr << ioe.getMsg() << endl << endl; exit(1);
		}

		// look if default config file exists
		if((cr.cfg_filename==0) & (def_cfg_fn!=0)) {
				cerr << "no config file given, looking for default config file \""
						 << def_cfg_fn << "\"" << endl << endl;

				ifstream dummy(def_cfg_fn, ios::in);
				if(dummy.is_open()) {
						cr.cfg_filename = new char[strlen(def_cfg_fn)+1];
						strcpy(cr.cfg_filename,def_cfg_fn);
						dummy.close();
				} 
		}
  
		// read config file
		if(cr.cfg_filename) {
				cerr << "using config file \"" << cr.cfg_filename << "\"\n\n";
				try {	cr.readConfigFile(); }
				catch(IOError ioe) { cerr << ioe.getMsg() << "\n\n"; exit(1); }
		} else cerr << "using no config file\n\n";
		proc_opts(cr.fargc,cr.fargv); // process options from config file
}
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
void show_settings()
/*---------------------------------------------------------------------------*/
{
		cerr << "settings:" << endl;
		cerr << hex 
				 << setw(20) << right << "adc0_addr = "<<"0x"  << adc0_addr  << endl
				 << setw(20) << right << "adc1_addr = "<<"0x"  << adc1_addr  << endl
				 << setw(20) << right << "adc2_addr = "<<"0x"  << adc2_addr  << endl
				 << setw(20) << right << "adc3_addr = "<<"0x"  << adc3_addr  << endl
				 << setw(20) << right << "tdc_addr = "<<"0x"   << tdc_addr   << endl
				 << setw(20) << right << "tdc_ch1 = " << dec   << tdc_ch1    << endl
				 << setw(20) << right << "tdc_ch2 = "          << tdc_ch2    << endl
				 << setw(20) << right << "tdc_width = "        << tdc_width  << endl
				 << setw(20) << right << "tdc_offset = " << tdc_offset << hex << endl
				 << setw(20) << right << "latch_addr = " << "0x" << latch_addr << endl
				 << setw(20) << right << "io_addr = "<<"0x"    << io_addr    << endl
				 << setw(20) << right << "cnt1_addr = "<<"0x"  << cnt1_addr  << endl
				 << setw(20) << right << "cnt2_addr = "<<"0x" << cnt2_addr  << endl
				 << setw(20) << right << "tc_addr = "<<"0x"   << tc_addr << endl
				 << setw(20) << right << "startstop_addr = " << "0x" << startstop_addr
				 <<"\n" << dec
				 << setw(20) << right << "measuretime = "  << measuretime << "\n"
#if 0
				 << setw(20) << right << "mtus = "         << mtus << "\n"
#endif
				 << setw(20) << right << "mtu = " << "0x"  << hex << mtu << "\n" << dec
				 << setw(20) << right << "sleeptime = "    << sleeptime  << " us\n"
				 << setw(20) << right << "dev_fn = "       << dev_fn     << endl
				 << setw(20) << right << "out_fn = "       << out_fn     << endl
				 << setw(20) << right << "log_fn = "       << log_fn     << endl
				 << setw(20) << right << "gz_level = "     << gz_level   << endl
				 << setw(20) << right << "sf_schema = "    << sf_schema  << endl
				 << setw(20) << right << "sfs_length = "   << sfs_length << endl
				 << setw(20) << right << "sf_loops = "     << sf_loops   << endl
				 << setw(20) << right << "sf_pause = "     << sf_pause   << " us\n"
				 << setw(20) << right << "only_test = "    << only_test  << endl
				 << setw(20) << right << "max_delta = "    << max_delta  << endl
				 << setw(20) << right << "min_delta = "    << min_delta  << endl
				 << endl << dec;
}
/*---------------------------------------------------------------------------*/


#define SIS3100_VERSION 0x0
/*---------------------------------------------------------------------------*/
void show_SIS3100_status(int handle) throw(IOError)
/*---------------------------------------------------------------------------*/
{
		u_int32_t d;
		int r;

		cerr << "SIS3100 status:";
		if((r=s3100_control_read(handle,SIS3100_VERSION,&d))) {
				stringstream ss;

				ss << "show_SIS3100_status():\n"
					 << "  s3100_control_read() returned " << r << "\n";

				throw IOError(ss.str().c_str(),r);
		}
		cerr << " FW Version: " << ((d & 0xff000000)>>24)
				 << " FW ID: " << ((d & 0x00ff0000)>>16)
				 << " HW Version: " << ((d & 0x0000ff00)>>8)
				 << " Identifier: " << (d & 0x000000ff) << endl;
}
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
void show_help(char *progname)
/*---------------------------------------------------------------------------*/
{
		cerr
				<< "usage: " << progname << " [options]\n\n"
				<< "options:" << endl <<
				" -h, --help                               shows this help\n"
				" -e, --test                               only show settings and exit\n"
				" -f <file>,   --config-file <file>        use <file> as config file\n"
				" -c <comment>,--comment <comment>         use <file> as config file\n"
				"\n"
				" ADC settings:\n"
				" -A <addr>,   --adc0-addr <addr>          set address of adc0 (in hex)\n"
				" -B <addr>,   --adc1-addr <addr>          set address of adc1 (in hex)\n"
				" -C <addr>,   --adc2-addr <addr>          set address of adc2 (in hex)\n"
				" -D <addr>,   --adc3-addr <addr>          set address of adc3 (in hex)\n\n"
				" TDC settings:\n"
				" -T <addr>,   --tdc-addr <addr>           set tdc address (in hex)\n"
				" -E <ch#>,    --tdc-channel1 <ch#>        set tdc channel 1\n"
				" -F <ch#>,    --tdc-channel2 <ch#>        set tdc channel 2\n"
				" -G <tics>,   --tdc-window-width <tics>   set tdc window width (clock tics)\n"
				" -H <tics>,   --tdc-window-offset <tics>  set tdc offset (clock tics)\n\n"
				" other settings:\n"
				" -U <addr>,   --tc-addr <addr>            set tc address (in hex format)\n"
				" -L <addr>,   --latch-addr <addr>         set latch address (in hex format)\n"
				" -I <addr>,   --io-addr <addr>            set io module address (in hex)\n"
				" -J <addr>,   --cnt1-addr <addr>          set counter1 address (in hex)\n"
				" -K <addr>,   --cnt2-addr <addr>          set counter2 address (in hex)\n"
				" -M <addr>,   --startstop-addr <addr>     set startstop address (in hex)\n"
				" -Q <addr>,   --qdc-addr <addr>           set qdc v792 address (in hex)\n"
				" -d <path>,   --sis1100-device <path>     set sis1100 device file to <path>\n"
				" -t <time>,   --measure-time <time>       set measure time (in s)\n"
				" -u <unit>,   --measure-time-unit <unit>  set unit for measuretime, can be:\n"
				"                                          100ns,1us,10us,100us,1ms,10ms,100ms\n"
				" -s <time>,   --sleep-time <time>         set sleep time (in us)\n"
				" -z <level>,  --gz-level <level>          set gz compression level\n"
				" -o <file>,   --data-file <file>          set output file\n"
				" -l <file>,   --log-file <file>           set log file\n"
				" -S <schema>, --spin-flip-schema <schema> set spin flip schema\n"
				" -r <loops>,  --spin-flip-loops <loops>   set number of spin flip loops\n"
				" -p <time>,   --spin-flip-pause <time>    pause between spinflips (in us)\n"
				" -m <time>,   --max-delta <events>        max_number of events per readout\n"
				"\nMeasurement modus flags:\n"
				" -q <n>,      --src <n>                   using calibration source n\n"
				" -a,          --scan                      a scan is done\n"
				" -N,          --h1c                       shutter h113 closed\n"
				" -O,          --sdc                       shutter down closed\n"
				" -P,          --suc                       shutter up closed\n"
				" if no modus flag is given, it is assumed that all shutters are open\n"
				" and no calibration sources are used.\n"
				"\n"
				"all numbers must be given in decimal format, if not explecitly specified\n"
				<< endl;
}
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
void proc_opts(int largc, char *largv[])
/*---------------------------------------------------------------------------*/
{
		static struct option long_options[] =
				{
						{"adc0-addr",         required_argument, 0, 'A'},
						{"adc1-addr",         required_argument, 0, 'B'},
						{"adc2-addr",         required_argument, 0, 'C'},
						{"adc3-addr",         required_argument, 0, 'D'},
						{"tdc-channel1",      required_argument, 0, 'E'},
						{"tdc-channel2",      required_argument, 0, 'F'},
						{"tdc-window-width",  required_argument, 0, 'G'},
						{"tdc-window-offset", required_argument, 0, 'H'},
						{"io-addr",           required_argument, 0, 'I'},
						{"cnt1-addr",         required_argument, 0, 'J'},
						{"cnt2-addr",         required_argument, 0, 'K'},
						{"latch-addr",        required_argument, 0, 'L'},
						{"startstop-addr",    required_argument, 0, 'M'},
						{"h1c",               no_argument,       0, 'N'},
						{"sdc",               no_argument,       0, 'O'},
						{"suc",               no_argument,       0, 'P'},
						{"qdc-addr",          required_argument, 0, 'Q'},
						{"spin-flip-schema",  required_argument, 0, 'S'},
						{"tdc-addr",          required_argument, 0, 'T'},
						{"tc-addr",           required_argument, 0, 'U'},
						{"scan",              no_argument,       0, 'a'},
						{"comment",           required_argument, 0, 'c'},
						{"sis1100-device",    required_argument, 0, 'd'},
						{"test",              no_argument,       0, 'e'},
						{"help",              no_argument,       0, 'h'},
						{"data-file",         required_argument, 0, 'o'},
						{"log-file",          required_argument, 0, 'l'},
						{"max-delta",         required_argument, 0, 'm'},
						{"max-delta",         required_argument, 0, 'n'},
						{"spin-flip-pause",   required_argument, 0, 'p'},
						{"src",               required_argument, 0, 'q'},
						{"spin-flip-loops",   required_argument, 0, 'r'},
						{"sleep-time",        required_argument, 0, 's'},
						{"measure-time",      required_argument, 0, 't'},
//removed 20070316 by alex, because measuretime is now always given in seconds
#if 0
						{"measure-time-unit", required_argument, 0, 'u'},
#endif 
						{"gz-level",          required_argument, 0, 'z'},
						{0, 0, 0, 0}
				};

		optind=0; // important! if getopt_long() is used to processes
		// more than one array, as done in main()
		while(1) {
				/* getopt_long stores the option index here. */
				int option_index = 0;
				int c;
				unsigned tmp;

				// important: without this statement getopt_long() does not
				//            terminate processing of arguments correctly
				if(optind>=largc) break;

				c = getopt_long(largc, largv,
												"A:B:C:D:E:F:G:H:I:J:K:L:M:N:O:P:Q:S:T:U:"
												"c:d:ehl:m:n:o:p:q:r:s:t:u:z:",
												long_options, &option_index);    

				if (c == -1) break; // Detect the end of the options.
				// this does not work correctly if you use
				// cr.fargc and cr.fargv! (see above)

				switch(c) {
						case 'h':
								show_help(largv[0]);
								exit(0);
								break;
						case 'e':
								only_test = 1;
								break;
						case 'A':
								sscanf(optarg,"%x",&adc0_addr);
								break;
						case 'B':
								sscanf(optarg,"%x",&adc1_addr);
								break;
						case 'C':
								sscanf(optarg,"%x",&adc2_addr);
								break;
						case 'D':
								sscanf(optarg,"%x",&adc3_addr);
								break;
						case 'Q':
								sscanf(optarg,"%x",&qdc_addr);
								break;
						case 'T':
								sscanf(optarg,"%x",&tdc_addr);
								break;
						case 'E':
								sscanf(optarg,"%d",&tdc_ch1);
								break;
						case 'F':
								sscanf(optarg,"%d",&tdc_ch2);
								break;
						case 'G':
								sscanf(optarg,"%d",&tdc_width);
								break;
						case 'H':
								sscanf(optarg,"%d",&tdc_offset);
								break;
						case 'U':
								sscanf(optarg,"%x",&tc_addr);
								break;
						case 'L':
								sscanf(optarg,"%x",&latch_addr);
								break;
						case 'I':
								sscanf(optarg,"%x",&io_addr);
								break;
						case 'J':
								sscanf(optarg,"%x",&cnt1_addr);
								break;
						case 'K':
								sscanf(optarg,"%x",&cnt2_addr);
								break;
						case 'M':
								sscanf(optarg,"%x",&startstop_addr);
								break;
						case 't':
								sscanf(optarg,"%d",&measuretime);
								break;
						case 's':
								sscanf(optarg,"%d",&sleeptime);
								break;
						case 'z':
								sscanf(optarg,"%d",&gz_level);
								break;
						case 'd':
								dev_fn = new char[strlen(optarg)+1];
								if(dev_fn) strcpy(dev_fn,optarg);
								break;
						case 'o':
								out_fn = new char[strlen(optarg)+1];
								if(out_fn) strcpy(out_fn,optarg);
								break;
						case 'l':
								log_fn = new char[strlen(optarg)+1];
								if(log_fn) strcpy(log_fn,optarg);
								break;
						case 'S':
								sf_schema = new char[strlen(optarg)+1];
								if(sf_schema) strcpy(sf_schema,optarg);
								break;
						case 'c':
								comment = new char[strlen(optarg)+1];
								if(comment) strcpy(comment,optarg);
								break;
						case 'r':
								sscanf(optarg,"%d",&sf_loops);
								break;
						case 'p':
								sscanf(optarg,"%d",&sf_pause);
								break;
						case 'm':
								sscanf(optarg,"%d",&max_delta);
								break;
						case 'n':
								sscanf(optarg,"%d",&min_delta);
								break;
//removed 20070316 by alex, because measuretime is now always given in seconds
//(asuming a 10 Mhz clock is fed into the start stop module)
#if 0
						case 'u':
								mtus = new char[strlen(optarg)+1];
								if(mtus) strcpy(mtus,optarg);

								if(!strcasecmp(mtus,"100ns"))
										mtu = StartStop::TB_100ns;
								else if(!strcasecmp(mtus,"1us"))
										mtu = StartStop::TB_1us;
								else if(!strcasecmp(mtus,"10us"))
										mtu = StartStop::TB_10us;
								else if(!strcasecmp(mtus,"100us"))
										mtu = StartStop::TB_100us;
								else if(!strcasecmp(mtus,"1ms"))
										mtu = StartStop::TB_1ms;
								else if(!strcasecmp(mtus,"10ms"))
										mtu = StartStop::TB_10ms;
								else if(!strcasecmp(mtus,"100ms"))
										mtu = StartStop::TB_100ms;
								else {
										cerr << "error: unknown measure time unit \""
												 << mtus <<"\"\n\n";
										exit(1);
								}
								break;
#endif
//added 2007032 by alex; todo: check if this works!
						case 'q': //set which source is used --> beam must be off then
								sscanf(optarg,"%d",&tmp);
								if( (1 <= tmp) || (tmp <= 5) ) {
										modus &= 0xfffe;
										modus |= (0x0001 << (3+tmp));
								}
								break;
						case 'N': // h113 closed -> no beam!
								modus &= 0xfffe; //clear bit 0
								modus |= 0x0002; //set bit 1, this is somehow redundant
								break;
						case 'O': // shutter down closed
								modus |= 0x0008; //set bit 3
								break;
						case 'P': // shutter up closed
								modus |= 0x0004; //set bit 2
								break;
						case 'a': // scan is done
								modus |= 0x0200; //set bit 9
								break;
						case '?':
								cerr << "-- exiting because of unknown option --\n\n";
								exit( 1 );
								break;
						default:
								cerr << "-- exiting because of unknown option --\n\n";
								exit( 1 );
								break;
				}
		}
		sfs_length = strlen(sf_schema);
}
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
void read_hw()
/*---------------------------------------------------------------------------*/
{
	qdc->ReadEvents(ev,delta);
	tc->ReadEvents(ev,delta);
	latch->ReadEvents(ev,delta);

		// read TDC
    for(u_int32_t i=0; i< delta; i++) {
				u_int32_t r	= readTDCEvent(&(ev[i].tdc1), TDC_STOPS, &(tdc_numstops[i]), &tdc_zeroevents);

				if( (r==0) && (last_tdc_en==1023) ) tdc_eco++;
				else if((last_tdc_en+1) != r) {
						stringstream ss;

						ss << "read_hw(): error: last_tdc_en==" << last_tdc_en
							 << "  r==" << r << endl;

						throw IOError( ss.str().c_str(),r );
				}
				last_tdc_en = r;
    }
}
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
void write_data()
/*---------------------------------------------------------------------------*/
{
    u_int32_t tc_data=0;

    // rearange data and write to file
    for(u_int32_t i=0; i<delta; i++) {

				// build tc data
				tc_data = ((0x00ff & tcbuf[2*i+1])<<16) | (0xffff & tcbuf[2*i]);

				// do latch stuff 
				//the upper eight bits in latch are used as status flags!
				ev[i].latch &= 0x00ffffff;
//added 20070328
				status_flags &= ~ (0x07 << 3);                 //set bits 5-3 to zero
				status_flags |= (tdc_numstops[i] & 0x07) << 3; //save number of tdc stops to
				                                               // bits 5-3

//removed 20070328
//				if( tdcbuf[i][2] != 0 )    //there have been more than 2 tdc stops
//						status_flags |= 0x20;  // sets bit 5 to 1 (bits counted from 0)
//				else
//						status_flags &= 0xdf;  // sets bit 5 to 0 (bits counted from 0)				
//				if( tdcbuf[i][3] !=0 )     // there have been more than 3 tdc stops
//						status_flags |= 0x10;  // sets bit 4 to 1 (bits counted from 0)
//				else
//						status_flags &= 0xef;  // sets bit 4 to 0 (bits counted from 0)

				ev[i].latch |= (((u_int32_t)status_flags) << 24);				

/*
	cout << "write_data(): status_flags= 0x"
	<< hex << (((u_int32_t)status_flags)<<24)
	<< "  latch_data = 0x" << latch_data
	<< dec << endl;
*/

				// do tdc stuff: TODO!
	}

#if TIME_PROFILE
				TM_START();
#endif
				gzwrite(gzout,(const voidp)ev,sizeof(EventStruct)*delta);
#if TIME_PROFILE
				TM_STOP();
				gzWriteTime += tm_secs;
#endif

    //at this time tc_data holds the time of the last word read
    if(hitcounter - rate_hc > 1000) {
				rate = ((double)(hitcounter-rate_hc))/(tc_data-rate_tc) * 1000;

				rate_tc = tc_data;
				rate_hc = hitcounter;
    }

}
/*---------------------------------------------------------------------------*/


// returns the event number, extracted from header
/*---------------------------------------------------------------------------*/
u_int32_t readTDCEvent(u_int32_t *buf, u_int32_t bufsize,
											 u_int32_t *tdc_numstops, u_int32_t *tdc_zeroevents)
		throw (IOError)
/*---------------------------------------------------------------------------*/
{
    u_int32_t d;

    if(!bufsize)
				throw IOError("readTDCEvent():\n"
											"  invalid bufsize (=0)",bufsize);

		//clear buf: be careful! added 2007-03-22 00:19
		//tdc data before this date is probably random!
		for(unsigned i=0; i<bufsize; i++) buf[i]=0;

    u_int32_t retries=0;


    do { d=tdc_br->readWord(); retries++; }
//    do { d=tdc->readWord(); retries++; }
    while(    (retries < tdc_br_cs)
							&& ((d & TDC_V767::TYPE_MASK) != TDC_V767::HEADER) );

    if( retries >= tdc_br_cs )
				throw IOError("readTDCEvent():\n  header expected",d);

		//extract event number from header
    u_int32_t r = d & TDC_V767::EN_MASK;

		*tdc_numstops = 0; u_int32_t eob_numstops;
    do {
				d=tdc_br->readWord();
//				d=tdc->readWord();

				if( (d & TDC_V767::TYPE_MASK) == TDC_V767::IV_DATA )
						throw IOError("readTDCEvent():\n  invalid data",d);	

				if( (d & TDC_V767::TYPE_MASK) == TDC_V767::EOB) {
						if( (d & TDC_V767::EOB_STATUS_MASK) == TDC_V767::EOB_STATUS_ERROR )
								throw IOError("readTDCEvent(): TDC chip error",d);

						eob_numstops = (d & TDC_V767::EOB_EVENT_DATA_COUNTER);
						if( eob_numstops != *tdc_numstops )
								throw IOError( "readTDCEvent(): number of stops read"
															 " is different from that given in EOB",d );
						break;
				}

				if( (d & TDC_V767::TYPE_MASK) == TDC_V767::VALID_DATA ) {
						if( *tdc_numstops >= bufsize ) {
//						throw IOError("readTDCEvent():\n"
//													"  to many time values for buffer",d);

								cerr << "readTDCEvent():"
										 << "  warning: too many time values for buffer: "
										 << "tdc_numstops=" << *tdc_numstops << " bufsize="
										 << bufsize << "\n"
										 << "  continue ignoring data...\n";
						} else {
								buf[*tdc_numstops] = d;
						}
						(*tdc_numstops)++;
				}
    } while(1);

		if(*tdc_numstops > 7) {
				cerr << "readTDCEvent(): there are " << *tdc_numstops
						 << " tdc stop events saving as 7\n";
				*tdc_numstops = 7;
		}

		if( *tdc_numstops == 0 ) {
//				cerr << "readTDCEvent(): warning: tdc_numstops==0, eob_numstops="
//						 << eob_numstops << endl;

				(*tdc_zeroevents)++;
		}

    return r;
}
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
void signal_handler(int signal)
/*---------------------------------------------------------------------------*/
{
		if(signal == SIGINT) {
				cerr << "\n\nCTRL-C pressed\n";
				safe_exit(2);
		} else
				psignal(signal, "signal_handler(): unknown signal!");
}
/*---------------------------------------------------------------------------*/


/*---------------------------------------------------------------------------*/
void safe_exit(int r)
/*---------------------------------------------------------------------------*/
{
		cerr << "\nsafe_exit()\n";

    if(crate > -1 ) {
				setFlipper( '0' );
				cerr << "vmesysreset...";
				if(int r=vmesysreset(crate)) {
						cerr << "error: vmesysreset() returned " << r << endl << endl;
						cerr.flush(); exit(1);
				}
				sleep(1);	cerr << "ok\n";

				cerr << "closing crate\n\n"; close(crate);
		}

		exit(r);
}
/*---------------------------------------------------------------------------*/

/*---------------------------------------------------------------------------*/
void read_cycleno()
/*---------------------------------------------------------------------------*/
{
    std::ifstream in(CYCLE_FN);

    if(!in)
		{
				throw IOError((string("read_cycleno():\n"
															"  error by opening file \"") + CYCLE_FN +"\"\n\n").c_str()
											,0);		
		}

		in >> fcID;

		in.close();
}
/*---------------------------------------------------------------------------*/

//write next cycles' id number to file
//open file that contains next fcID for writing
/*---------------------------------------------------------------------------*/
void write_nextcycleno()
/*---------------------------------------------------------------------------*/
{
		ofstream next_fcID_file(CYCLE_FN);

		if(!next_fcID_file) {
				throw IOError((string("write_nextcycleno():\n"
															"---- ERROR: could not open file \"") + CYCLE_FN
											 + "\" that contains next fcID for writing ----\n\n"
													).c_str(),0);
		}

		next_fcID_file << dec << (cur_cycle + fcID);
		next_fcID_file.close();
}
/*---------------------------------------------------------------------------*/
